#!/usr/bin/perl -w
use strict;

# Copyright 2008, Andrew Ross andy@plausible.org
# Distributable under the terms of the GNU GPL, see COPYING for details

# The Android toolchain is ... rough.  Rather than try to manage the
# complexity directly, this script wraps the tools into an "agcc" that
# works a lot like a gcc command line does for a native platform or a
# properly integrated cross-compiler.  It accepts arbitrary arguments,
# but interprets the following specially:
#
# -E/-S/-c/-shared - Enable needed arguments (linker flags, include
#                    directories, runtime startup objects...) for the
#                    specified compilation mode when building under
#                    android.
#
# -O<any> - Turn on the optimizer flags used by the Dalvik build.  No
#           control is provided over low-level optimizer flags.
#
# -W<any> - Turn on the warning flags used by the Dalvik build.  No
#           control is provided over specific gcc warning flags.
#
# Notes:
# + The prebuilt arm-eabi-gcc from a built (!) android source
#   directory must be on your PATH.
# + All files are compiled with -fPIC to an ARMv5TE target.  No
#   support is provided for thumb.
# + No need to pass a "-Wl,-soname" argument when linking with
#   -shared, it uses the file name always (so don't pass a directory in
#   the output path for a shared library!)

# Some modifications to build NEURON
# C. Schmidt-Hieber, 2011-05-30

# Dance around to find the actual android toolchain path (it's very
# deep, so links on $PATH are going to be common.
# die "bad arm-linux-androideabi-gcc path" if $GCC !~ /(.*)\/prebuilt\//;
my $HOME = $ENV{"HOME"};
my $TARGET = "android-15";
my $TOOLCHAIN = "$HOME/android-toolchain";
my $MSYSROOT = "$TOOLCHAIN/sysroot";
my $GCC = "$TOOLCHAIN/bin/arm-linux-androideabi-gcc";

my @include_paths = ("-I$MSYSROOT/usr/include");

my @preprocess_args = (
    "-D__ARM_ARCH_5__",
    "-D__ARM_ARCH_5T__",
    "-D__ARM_ARCH_5E__",
    "-D__ARM_ARCH_5TE__", # Already defined by toolchain
    "-DANDROID",
    "-DNDEBUG");

my @warn_args = (
    "-Wno-psabi"); # Implicit in -Wall per texinfo

my @compile_args = (
    "-MMD",
    "-MP",
    "-march=armv5te",
    "-mtune=xscale",
    "-msoft-float",
    "-mthumb",
    "-fpic",
    "-ffunction-sections",
    "-funwind-tables",
    "-fstack-protector",
    "-no-canonical-prefixes",
    "-fPIE",
    "-Wa,--noexecstack" ); # check guard variable before return
    
my @optimize_args = (
    "-O2",
    "-finline-limit=64",
    "-fomit-frame-pointer",
    "-fno-strict-aliasing");

my @link_args = (
    "-Wl,--gc-sections",
    "-Wl,-z,nocopyreloc",
    "--sysroot=$MSYSROOT",
    "$TOOLCHAIN/lib/gcc/arm-linux-androideabi/4.8/libgcc.a",
    "-Wl,--no-undefined",
    "-Wl,-z,noexecstack",
    "-fPIE",
    "-pie",
    "-lc",
    "-lm");
    
# Also need: -Wl,-soname,libXXXX.so
my @shared_args = (
    "-Wl,--sysroot=$MSYSROOT",
    "-Wl,--gc-sections",
    "-Wl,-shared,-Bsymbolic",
    "-Wl,--no-whole-archive",
    "-lc",
    "-lm",
    "-Wl,--no-undefined",
    "-Wl,-z,noexecstack",
    "$TOOLCHAIN/lib/gcc/arm-linux-androideabi/4.8/libgcc.a",
    "-Wl,--whole-archive"); # .a, .o input files go *after* here

# Now implement a quick parser for a gcc-like command line

my %MODES = ("-E"=>1, "-c"=>1, "-S"=>1, "-shared"=>1);

my $mode = "DEFAULT";
my $out;
my $warn = 0;
my $opt = 0;
my @args = ();
my $have_src = 0;
while(@ARGV) {
    my $a = shift;
    if(defined $MODES{$a}) {
    die "Can't specify $a and $mode" if $mode ne "DEFAULT";
    $mode = $a;
    } elsif($a eq "-o") {
    die "Missing -o argument" if !@ARGV;
    die "Duplicate -o argument" if defined $out;
    $out = shift;
    } elsif($a =~ /^-W.*/) {
    $warn = 1;
    } elsif($a =~ /^-O.*/) {
    $opt = 1;
    } else {
    if($a =~ /\.(c|cpp|cxx)$/i) { $have_src = 1; }
    push @args, $a;
    }
}

my $need_cpp = 0;
my $need_compile = 0;
my $need_link = 0;
my $need_shlink = 0;
if($mode eq "DEFAULT") { $need_cpp = $need_compile = $need_link = 1; }
if($mode eq "-E") { $need_cpp = 1; }
if($mode eq "-c") { $need_cpp = $need_compile = 1; }
if($mode eq "-S") { $need_cpp = $need_compile = 1; }
if($mode eq "-shared") { $need_shlink = 1; }

if($have_src and $mode ne "-E") { $need_cpp = $need_compile = 1; }

# Assemble the command:
my @cmd = ("$GCC");
if($mode ne "DEFAULT") { @cmd = (@cmd, $mode); }
if(defined $out) { @cmd = (@cmd, "-o", $out); }
if($need_cpp) { @cmd = (@cmd, @include_paths, @preprocess_args); }
if($need_compile){
    @cmd = (@cmd, @compile_args);
    if($warn) { @cmd = (@cmd, @warn_args); }
    if($opt) { @cmd = (@cmd, @optimize_args); }
}
if($need_link) { @cmd = (@cmd, @link_args); }
if($need_shlink) { @cmd = (@cmd, @shared_args); }
@cmd = (@cmd, @args);

#print join(" ", @cmd), "\n"; # Spit it out if you're curious
exec(@cmd);
